// --------------------------------------------------------------------
// >>>>>>>>>>>>>>>>>>>>>>>>> COPYRIGHT NOTICE <<<<<<<<<<<<<<<<<<<<<<<<<
// --------------------------------------------------------------------
// Copyright (c) 2006 by Lattice Semiconductor Corporation
// --------------------------------------------------------------------
//
// Permission:
//
//   Lattice Semiconductor grants permission to use this code for use
//   in synthesis for any Lattice programmable logic product.  Other
//   use of this code, including the selling or duplication of any
//   portion is strictly prohibited.
//
// Disclaimer:
//
//   This VHDL or Verilog source code is intended as a design reference
//   which illustrates how these types of functions can be implemented.
//   It is the user's responsibility to verify their design for
//   consistency and functionality through the use of formal
//   verification methods.  Lattice Semiconductor provides no warranty
//   regarding the use or functionality of this code.
//
// --------------------------------------------------------------------
//           
//                     Lattice Semiconductor Corporation
//                     5555 NE Moore Court
//                     Hillsboro, OR 97214
//                     U.S.A
//
//                     TEL: 1-800-Lattice (USA and Canada)
//                          503-268-8001 (other locations)
//
//                     web: http://www.latticesemi.com/
//                     email: techsupport@latticesemi.com
//
// --------------------------------------------------------------------
//
//  Project:           7:1 LVDS Video Interface
//  File:              LVDS_7_to_1_TX.v
//  Title:             LVDS_7_to_1_TX
//  Description:       Tx module of this reference design
//
// --------------------------------------------------------------------
//
// Revision History :
// --------------------------------------------------------------------
// $Log: LVDS_7_to_1_TX.vhd,v $
// Revision 1.0  2006-09-25 19:46:52-07  jhsin
// Revision 1.1  2007-11-12  hchen
//
// --------------------------------------------------------------------

`timescale 1 ns/ 1 ps
//`define sim_special

module LVDS_7_to_1_TX 
     (
      CLK_Tx  ,
      RST_Tx  ,
              
      TA_in   ,
      TB_in   ,
      TC_in   ,
      TD_in   ,
              
      TCLK_out,
      TA_out  ,
      TB_out  ,
      TC_out  ,
      TD_out  ,

      txpll_lock 
    );

   input        CLK_Tx;   // Tx module input clock 
   input        RST_Tx;   // Tx module reset
     
   input  [6:0] TA_in;    // 7-bit parallel data
   input  [6:0] TB_in;    // 7-bit parallel data
   input  [6:0] TC_in;    // 7-bit parallel data
   input  [6:0] TD_in;    // 7-bit parallel data
   
   output       TCLK_out; // LVDS clock output pair 
   output       TA_out;   // LVDS data output pair 0
   output       TB_out;   // LVDS data output pair 1
   output       TC_out;   // LVDS data output pair 2
   output       TD_out;   // LVDS data output pair 3
         
   output       txpll_lock;


   wire [6:0] txdata_in  [0:3];
   wire [3:0] txdata_odd [0:3];

   wire [3:0] txclk_odd;
   wire [3:0] tx_do;

   wire [2:0] tx_wr_state;
   wire [3:0] tx_rd_state;      
         
   wire eclk;
//   wire sclk;
   wire  eclk_sync;

   reg  sync_lock;
   wire tx_pll_lock;
   wire tx_reset;

      txpll PLL_INST
         (
          .CLK   (CLK_Tx),
          .RESET (RST_Tx),
          .CLKOP (),
          .CLKOS (eclk),
          .CLKOK (),
          .LOCK  (tx_pll_lock)
         );	

   always @(negedge tx_pll_lock or negedge CLK_Tx)
   begin
      if (tx_pll_lock == 1'b0)
         sync_lock <= 1'b0;
      else
         sync_lock <= 1'b1;
   end

reg tmp_rst;
   always @(negedge tx_pll_lock or posedge CLK_Tx)
   begin
      if (tx_pll_lock == 1'b0)
         tmp_rst <= 1'b1;
      else
         tmp_rst <= 1'b0;
   end

reg tx_rst_r1,tx_rst_r2;

   always @(posedge CLK_Tx or negedge sync_lock)
      if (!sync_lock)		  
      begin
         tx_rst_r1 <= 1'b1;
         tx_rst_r2 <= 1'b1;
      end
      else
      begin
         tx_rst_r1 <= tmp_rst;
         tx_rst_r2 <= tx_rst_r1;
      end

   assign txpll_lock  = sync_lock; 
   //assign tx_reset = ~sync_lock;
   //assign tx_reset = ~sync_lock || RST_Tx;
   assign tx_reset = tx_rst_r2;

ECLKSYNCA eclk_inst(.ECLKI(eclk), .STOP(tx_rst_r2), .ECLKO(eclk_sync));

`ifdef sim_special     
/*
   reg     sclk;
   always @(posedge eclk_sync or posedge tmp_rst)
      if (tmp_rst)
         sclk <= 1'b0;
      else
         sclk <= ~ sclk;
*/
wire sclk_tmp, sclk;
CLKDIVB u_div( .CLKI(eclk_sync), .RST(tmp_rst), .RELEASE(1'b1), .CDIV1(), .CDIV2(sclk_tmp), .CDIV4(), .CDIV8() );
assign #1 sclk = sclk_tmp;
`else
wire sclk;   
CLKDIVB u_div( .CLKI(eclk_sync), .RST(tmp_rst), .RELEASE(1'b1), .CDIV1(), .CDIV2(sclk), .CDIV4(), .CDIV8() );
`endif

//*******************************************************************************************
//for the new architecture of ECP3 high speed IO
//we should use 5 pairs of true lvds output pad, which require 3 DQSBUFE.

DQSBUFE1 Inst0_DQSBUFE (
   .ECLKW(eclk_sync), 
   .RST(/*tx_reset),*//*RST_Tx*/tmp_rst), 
   .DYNDELPOL(1'b0),
   .DYNDELAY6(1'b0),
   .DYNDELAY5(1'b0), 
   .DYNDELAY4(1'b0), 
   .DYNDELAY3(1'b0), 
   .DYNDELAY2(1'b0), 
   .DYNDELAY1(1'b0), 
   .DYNDELAY0(1'b0), 
   .DQCLK0(Inst0_dqclk0), 
   .DQCLK1(Inst0_dqclk1)
   );

tx_oddr_x2 txdata_0_inst
           (.SClk   (sclk),
            .dqclk0 (Inst0_dqclk0),
            .dqclk1 (Inst0_dqclk1),
            .Data (txdata_odd[0]),
            .Q (tx_do[0])
           );   
           
tx_oddr_x2 txdata_1_inst
           (.SClk   (sclk),
            .dqclk0 (Inst0_dqclk0),
            .dqclk1 (Inst0_dqclk1),
            .Data (txdata_odd[1]),
            .Q (tx_do[1])
           );

DQSBUFE1 Inst1_DQSBUFE (
   .ECLKW(eclk_sync), 
   .RST(/*tx_reset),*//*RST_Tx*/tmp_rst), 
   .DYNDELPOL(1'b0),
   .DYNDELAY6(1'b0),
   .DYNDELAY5(1'b0), 
   .DYNDELAY4(1'b0), 
   .DYNDELAY3(1'b0), 
   .DYNDELAY2(1'b0), 
   .DYNDELAY1(1'b0), 
   .DYNDELAY0(1'b0), 
   .DQCLK0(Inst1_dqclk0), 
   .DQCLK1(Inst1_dqclk1)
   );
           
tx_oddr_x2 txdata_2_inst          
           (.SClk   (sclk),       
            .dqclk0 (Inst1_dqclk0),     
            .dqclk1 (Inst1_dqclk1),     
            .Data (txdata_odd[2]),
            .Q (tx_do[2])         
           );                                

tx_oddr_x2 txdata_clk_inst
           (.SClk   (sclk),
            .dqclk0 (Inst1_dqclk0),
            .dqclk1 (Inst1_dqclk1),
            .Data (txclk_odd),
            .Q (TCLK_out)
           );           

wire Inst2_dqclk0, Inst2_dqclk1;
         
DQSBUFE1 Inst2_DQSBUFE (
   .ECLKW(eclk_sync), 
   .RST(/*tx_reset),*//*RST_Tx*/tmp_rst), 
   .DYNDELPOL(1'b0),
   .DYNDELAY6(1'b0),
   .DYNDELAY5(1'b0), 
   .DYNDELAY4(1'b0), 
   .DYNDELAY3(1'b0), 
   .DYNDELAY2(1'b0), 
   .DYNDELAY1(1'b0), 
   .DYNDELAY0(1'b0), 
   .DQCLK0(Inst2_dqclk0), 
   .DQCLK1(Inst2_dqclk1)
   );

tx_oddr_x2 txdata_3_inst          
           (.SClk   (sclk),       
            .dqclk0 (Inst2_dqclk0),     
            .dqclk1 (Inst2_dqclk1),     
            .Data (txdata_odd[3]),
            .Q (tx_do[3])         
           );                                           
   

//*******************************************************************************************
      ser_fsm ser_fsm_inst
              (
               .TXCLK   (CLK_Tx),
               .CLK     (sclk),
               .RST     (tx_reset),
               .tx_wr_state (tx_wr_state),
               .tx_rd_state (tx_rd_state)
              );
         
   //--------------------------------------------------------------------
   //-- Data pair 0 ~ 3
   //--------------------------------------------------------------------
   
      assign txdata_in[0] = TA_in;
      assign txdata_in[1] = TB_in;
      assign txdata_in[2] = TC_in;
      assign txdata_in[3] = TD_in;
 
   
   genvar i;
   
   generate
   for (i=0; i < 4; i=i+1)
   begin : u
      serializer ser_inst 
                 (
                  .TXCLK   (CLK_Tx),
                  .CLK     (sclk),
                  .DATAIN  (txdata_in[i]),
                  .RST     (tx_reset),
                  .tx_wr_state (tx_wr_state),
                  .tx_rd_state (tx_rd_state),         
                  .DATAOUT (txdata_odd[i])
                 );


    end
    endgenerate


   assign TA_out = tx_do[0];
   assign TB_out = tx_do[1];
   assign TC_out = tx_do[2];
   assign TD_out = tx_do[3];

   //--------------------------------------------------------------------
   //-- Clock pair
   //--------------------------------------------------------------------

   // Note that using "1100011" for generating the clock will make a
   // "2-bit shifting" between the clock and data pairs.  This shift
   // is required for compatibility with National Semiconductor's
   // CameraLink LVDS chips.
   //             __________________                 __________________
   // Clock _____/           1    1 \__0____0____0__/ 1    1           \
   //        ___  ___  ___  ___  ___  ___  ___  ___  ___  ___  ___  ___ 
   // Data  /   \/   \/   \/bit\/bit\/bit\/bit\/bit\/bit\/bit\/   \/   \
   //       \___/\___/\___/\_6_/\_5_/\_4_/\_3_/\_2_/\_1_/\_0_/\___/\___/
   //

   serializer_txclk ser_clk_inst
             (
              .CLK     (sclk),
              .DATAIN  (7'b1100011),
              .RST     (tx_reset),
              .tx_rd_state (tx_rd_state),      
              .DATAOUT (txclk_odd)
             );



endmodule


